-- 运营活动: 密匙宝藏


--[[
{
    cmd_id = 1, -- 命令id，用于批量停止、删除活动 
    act_id = 56, -- 活动id (56 密匙宝藏)
    act_name = "密匙宝藏", -- 活动名称
    act_desc = "活动期间，玩家只要达到对应的充值金额，即可投入对应的元宝，赚取随机数额的元宝", -- 活动描述
    beg_time = 1493262000,  -- 活动开始时间(unix timestamp)
    end_time = 1593267400,  -- 活动结束时间(unix timestamp)
    config = -- 配置数据
    {
        eventList =  --抽奖次数 eventType = 1 活跃度  2为消费元宝
        {
            { eventType = 1, eventNum = 50, addCount = 1},
            { eventType = 1, eventNum = 100, addCount = 1},
            { eventType = 1, eventNum = 150, addCount = 1},
            { eventType = 1, eventNum = 200, addCount = 1},
            { eventType = 1, eventNum = 250, addCount = 1},
            { eventType = 2, eventNum = 50, addCount = 1},
            { eventType = 2, eventNum = 100, addCount = 1},
            { eventType = 2, eventNum = 150, addCount = 1},
            { eventType = 2, eventNum = 200, addCount = 1},
            { eventType = 2, eventNum = 250, addCount = 1},
        },

        wordToScore = 50,    --相同数字转成积分

        ChoiceNumCostScore = 1000,  --选择数字消耗

        lineList =   --每条线
        {
            {
                needNumList = {1,2,3,4,5,6,7} --所需要获得的数字
                awards = {
                    {type = 0, id = 271, count = 1, bind = 1 , strong = 0 ,quality = 0 ,},
                },          
            },
        },

        exLineAwards = 
        {
            {
                lineNum = 1, --完成曲线条数 
                awards = {
                    {type = 0, id = 271, count = 1, bind = 1 , strong = 0 ,quality = 0 ,},
                },  
            },
        },

        rates = 
        {
            {
                cond = {1, 9},  --已获取的数字个数
                rate = 9000 ,   --获得不同数字的万分数
            },
            {
                cond = {10, 39},  --已获取的数字个数
                rate = 5000 ,   --获得不同数字的万分数
            },
            {
                cond = {40, 49},  --已获取的数字个数
                rate = 2000 ,   --获得不同数字的万分数
            },
        },
    },
}
]]

-- 检查配置是否正确，正确则返回 0，否则返回错误码
function oper_act_56_check_cfg(cfg)
    if cfg == nil then return 20 end
    
    local config = cfg.config
    if config == nil then return 21 end
    
    if config.lineList == nil then return 23 end
    if type(config.lineList) ~= "table" then return 24 end

    for id, lineInfo in ipairs(config.lineList) do
        if lineInfo == nil then return 25 end
        if type(lineInfo) ~= "table" then return 26 end
        if lineInfo.awards == nil then return 27 end
        if type(lineInfo.awards) ~= "table" then return 28 end
        if not oper_act_check_one_award_cfg(lineInfo.awards) then
            return 22
        end 
    end

    if config.exLineAwards == nil then return 29 end
    if type(config.exLineAwards) ~= "table" then return 30 end

    for id, exlineInfo in ipairs(config.exLineAwards) do
        if exlineInfo == nil then return 31 end
        if type(exlineInfo) ~= "table" then return 32 end
        if exlineInfo.awards == nil then return 33 end
        if type(exlineInfo.awards) ~= "table" then return 34 end
        if not oper_act_check_one_award_cfg(exlineInfo.awards) then
            return 35
        end 
    end

    return 0
end

-- 安装活动，成功则返回 0，否则返回错误码
function oper_act_56_setup(cfg) 
    return 0
end

-- 卸载活动
function oper_act_56_unsetup(cfg)   
end

-- 活动开始
function oper_act_56_start(cfg)
    local ssVar = System.getStaticVar()
    ssVar.oper_act_56_start = 1
    ssVar.oper_act_56_cmd = cfg.cmd_id
    ssVar.oper_act_56_act = cfg.act_id

    local data = gRankMgr_GetValueByIndx(0, RANK_DEFINE_OPERATION_56, 1)

    if data then
        local myData = BaseFuc_unserialize(data)
        if myData and myData.cmd_id and myData.cmd_id == cfg.cmd_id and myData.act_id and myData.act_id == cfg.act_id and
            myData.time and cfg.beg_time <= myData.time and  cfg.end_time > myData.time then
            return
        end
    end

    gRankMgr_Clear(RANK_DEFINE_OPERATION_56)
end

-- 活动结束
function oper_act_56_end(cfg)
    local ssVar = System.getStaticVar()
    ssVar.oper_act_56_start = nil
    ssVar.oper_act_56_cmd = nil
    ssVar.oper_act_56_act = nil

    if not cfg then return end
    local config = cfg.config
    if not config then return end
end

-- 打包数据
function oper_act_56_packet_data(sysarg, cfg)
    if not cfg then return end
    local config = cfg.config
    if not config then return end
    
    
    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_56, 1)

    local myData = BaseFuc_unserialize(data)
    

    if not myData then
        myData = {}
    end

    if not myData.myUseCount then
        myData.myUseCount = 0
    end

    if not myData.myBuyCount then
        myData.myBuyCount = 0
    end

    if not myData.myConsumeMoney then
        myData.myConsumeMoney = 0
    end

    if not myData.myActivityVal then
        myData.myActivityVal = 0 
    end

    if not myData.myNumbers then
        myData.myNumbers = {}
    end

    if not myData.myScore then
        myData.myScore = 0
    end

    local time = System.getSystemTime()

    if myData.mySelfTime and not System.isUnixTimeSameDay(myData.mySelfTime, time) then
        myData.myActivityVal = 0 
        myData.myConsumeMoney = 0
        myData.myUseCount = 0
    end

    if not myData.finishLine then
        myData.finishLine = {}
    end

    if not myData.exAwards then
        myData.exAwards = {}
    end

    local getCount = oper_act_56_get_count(config, myData.myActivityVal, myData.myConsumeMoney)
    
    local npack = oper_act_alloc_init_data_packet(sysarg, cfg.cmd_id, cfg.act_id)
    if (npack == nil) then
        return
    end

    local canBuyCountState = 0
    if cfg.end_time - time <= config.canBuySeconds then
        canBuyCountState = 1
    end
    DataPack.writeByte(npack, canBuyCountState)

    local len = #myData.myNumbers
    DataPack.writeByte(npack, len)
    if len > 0 then
        for idx = 1, len do
            DataPack.writeByte(npack, myData.myNumbers[idx] or 0)
        end
    end

    DataPack.writeShort(npack, myData.myActivityVal)
    DataPack.writeInt(npack, myData.myConsumeMoney)

    DataPack.writeByte(npack, getCount)
    DataPack.writeByte(npack, myData.myUseCount)
    DataPack.writeByte(npack, myData.myBuyCount)

    DataPack.writeInt(npack, myData.myScore)

    local newlen = #config.exLineAwards
    DataPack.writeByte(npack, newlen)
    for ii = 1, newlen do
        DataPack.writeByte(npack, ii)
        local state = myData.exAwards[ii] or 0
        DataPack.writeByte(npack, state)
    end

    local newlen2 = #config.lineList
    DataPack.writeByte(npack, newlen2)
    for iii = 1, newlen2 do
        DataPack.writeByte(npack, iii)
        local state = myData.finishLine[iii] or 0
        DataPack.writeByte(npack, state)
    end

    DataPack.flush(npack) 
end

-- 操作，返回操作结果，0为成功
function oper_act_56_do(sysarg, cfg, clientPkt)
    if cfg == nil then return end
    
    if cfg.state == nil or cfg.state ~= 1 then -- 不在活动中
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation001, ttFlyTip)
        return
    end
    
    local config = cfg.config
    if config == nil then -- 参数错误
        print("error, oper_act_56_do cfg.config confg error")
        return
    end

    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_56, 1)

    local myData = BaseFuc_unserialize(data)
    

    if not myData then
        myData = {}
    end

    if not myData.myUseCount then
        myData.myUseCount = 0
    end

    if not myData.myBuyCount then
        myData.myBuyCount = 0
    end

    if not myData.myConsumeMoney then
        myData.myConsumeMoney = 0
    end

    if not myData.myActivityVal then
        myData.myActivityVal = 0 
    end

    if not myData.myNumbers then
        myData.myNumbers = {}
    end

    if not myData.myScore then
        myData.myScore = 0
    end

    local time = System.getSystemTime()

    if myData.mySelfTime and not System.isUnixTimeSameDay(myData.mySelfTime, time) then
        myData.myActivityVal = 0 
        myData.myConsumeMoney = 0
        myData.myUseCount = 0
    end

    if not myData.finishLine then
        myData.finishLine = {}
    end

    if not myData.exAwards then
        myData.exAwards = {}
    end

    if config.totalNum <= #myData.myNumbers then
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation149, ttFlyTip)
        return
    end

    local hasRewardState = false

    local opType = DataPack.readByte(clientPkt)
    local getNum
    local getCount = oper_act_56_get_count(config, myData.myActivityVal, myData.myConsumeMoney)
    if opType == 1 then
        local curRateItem = GetElemByCond( config.rates, #myData.myNumbers ) 

        if not curRateItem then
            return
        end
        if cfg.end_time - time <= config.canBuySeconds and getCount <= myData.myUseCount then
            local myCostMoney = config.firstBuyCountCost + config.preCountAddCost * myData.myBuyCount
            if Actor.getMoneyCount(sysarg, mtYuanbao) < myCostMoney then
                Actor.sendItemLack( sysarg, qatYuanbao, 0, myCostMoney )
                return
            end

            if not Actor.delMoney( sysarg,mtYuanbao,myCostMoney,LogIds.OperationLogId056,Lang.LogTips.Operation056) then
                return
            end
            myData.myBuyCount = myData.myBuyCount + 1
        else
            if getCount <= myData.myUseCount then
                Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation142, ttFlyTip)
                return
            end
            myData.myUseCount = myData.myUseCount + 1
        end
        
        local curRate = curRateItem.rate

        local ranNum = System.getRandomNumber(10000)

        if ranNum < curRate then  --获得不同数字
            local newRanNum, inMyNumbers = getRandomNumberExpertList(config.totalNum, myData.myNumbers)
            if inMyNumbers then
                local newRanNum2 = System.getRandomNumber(#myData.myNumbers) + 1
                getNum = myData.myNumbers[newRanNum2]
                myData.myScore = myData.myScore + config.wordToScore

                Actor.sendTipmsg(sysarg, string.format(Lang.ScriptTips.Operation155, getNum, config.wordToScore), ttFlyTip)
            else
                table.insert(myData.myNumbers, newRanNum)
                getNum = newRanNum
                local finishLineNum = 0
                for idx = 1, #config.lineList do
                    local state = myData.finishLine[idx] or 0
                    if state == 0 then
                        local lineInfo = config.lineList[idx]
                        local canGetAward = oper_act_56_can_get_award(lineInfo.needNumList, myData.myNumbers)
                        if canGetAward then
                            hasRewardState = true
                            finishLineNum = finishLineNum + 1
                            myData.finishLine[idx] = 1
                            local actorId = Actor.getActorId(sysarg)
                            local title = Lang.ScriptTips.Operation143
                            local content = Lang.ScriptTips.Operation144

                            local sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
                            local vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)

                            Awards.GiveToMailById(actorId, lineInfo.awards, title, content, LogIds.OperationLogId056, Lang.LogTips.Operation056, vocation, sex)
                        end
                    else
                        finishLineNum = finishLineNum + 1
                    end
                end

                for idx = 1, #config.exLineAwards do
                    local state = myData.exAwards[idx] or 0
                    if state == 0 then
                        local exAwardInfo = config.exLineAwards[idx]
                        if finishLineNum >= exAwardInfo.lineNum then
                            hasRewardState = true
                            myData.exAwards[idx] = 1
                            local actorId = Actor.getActorId(sysarg)
                            local title = Lang.ScriptTips.Operation145
                            local content = string.format(Lang.ScriptTips.Operation146, exAwardInfo.lineNum)

                            local sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
                            local vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)

                            Awards.GiveToMailById(actorId, exAwardInfo.awards, title, content, LogIds.OperationLogId056, Lang.LogTips.Operation056, vocation, sex)
                        end
                    end
                end
            end
        else --获得相同数字
            local newRanNum = System.getRandomNumber(#myData.myNumbers) + 1
            getNum = myData.myNumbers[newRanNum]
            myData.myScore = myData.myScore + config.wordToScore

            Actor.sendTipmsg(sysarg, string.format(Lang.ScriptTips.Operation155, getNum, config.wordToScore), ttFlyTip)
        end

    elseif opType == 2 then
        getNum = DataPack.readByte(clientPkt)
        if getNum < 1 or getNum > config.totalNum then
            Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation141, ttFlyTip)
            return
        end
        if myData.myScore < config.ChoiceNumCostScore then
            Actor.sendTipmsg(sysarg,string.format(Lang.ScriptTips.Operation147, config.ChoiceNumCostScore), ttFlyTip)
            return 
        end
        for idd = 1, #myData.myNumbers do
            if myData.myNumbers[idd] == getNum then
                Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation148, ttFlyTip)
                return
            end
        end
        myData.myScore = myData.myScore - config.ChoiceNumCostScore
        table.insert(myData.myNumbers, getNum)
        local finishLineNum = 0
        for idx = 1, #config.lineList do
            local state = myData.finishLine[idx] or 0
            if state == 0 then
                local lineInfo = config.lineList[idx]
                local canGetAward = oper_act_56_can_get_award(lineInfo.needNumList, myData.myNumbers)
                if canGetAward then
                    hasRewardState = true
                    finishLineNum = finishLineNum + 1
                    myData.finishLine[idx] = 1
                    local actorId = Actor.getActorId(sysarg)
                    local title = Lang.ScriptTips.Operation143
                    local content = Lang.ScriptTips.Operation144

                    local sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
                    local vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)

                    Awards.GiveToMailById(actorId, lineInfo.awards, title, content, LogIds.OperationLogId056, Lang.LogTips.Operation056, vocation, sex)
                end
            else
                finishLineNum = finishLineNum + 1
            end
        end

        for idx = 1, #config.exLineAwards do
            local state = myData.exAwards[idx] or 0
            if state == 0 then
                local exAwardInfo = config.exLineAwards[idx]
                if finishLineNum >= exAwardInfo.lineNum then
                    myData.exAwards[idx] = 1
                    hasRewardState = true
                    local actorId = Actor.getActorId(sysarg)
                    local title = Lang.ScriptTips.Operation145
                    local content = string.format(Lang.ScriptTips.Operation146, exAwardInfo.lineNum)

                    local sex = Actor.getIntProperty(sysarg, PROP_ACTOR_SEX)
                    local vocation = Actor.getIntProperty(sysarg, PROP_ACTOR_VOCATION)

                    Awards.GiveToMailById(actorId, exAwardInfo.awards, title, content, LogIds.OperationLogId056, Lang.LogTips.Operation056, vocation, sex)
                end
            end
        end
    else
        return
    end

    if hasRewardState then
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation156, ttFlyTip)
    end

    if not myData.cmd_id then
        myData.cmd_id = cfg.cmd_id
        myData.act_id = cfg.act_id
        myData.time = time
    end

    myData.mySelfTime = time

    local newData = BaseFuc_serialize(myData)
    gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_56, 1, newData)

    local npack = oper_act_alloc_do_result_packet(sysarg, cfg.cmd_id, cfg.act_id, 0)
    if not npack then return end

    local canBuyCountState = 0
    if cfg.end_time - time <= config.canBuySeconds then
        canBuyCountState = 1
    end
    DataPack.writeByte(npack, canBuyCountState)
    DataPack.writeByte(npack, getNum)
    DataPack.writeShort(npack, myData.myActivityVal)
    DataPack.writeInt(npack, myData.myConsumeMoney)

    DataPack.writeByte(npack, getCount)
    DataPack.writeByte(npack, myData.myUseCount)
    DataPack.writeByte(npack, myData.myBuyCount)

    DataPack.writeInt(npack, myData.myScore)

    local newlen = #config.exLineAwards
    DataPack.writeByte(npack, newlen)
    for iii = 1, newlen do
        DataPack.writeByte(npack, iii)
        local state = myData.exAwards[iii] or 0
        DataPack.writeByte(npack, state)
    end

    local newlen2 = #config.lineList
    DataPack.writeByte(npack, newlen2)
    for iiii = 1, newlen2 do
        DataPack.writeByte(npack, iiii)
        local state = myData.finishLine[iiii] or 0
        DataPack.writeByte(npack, state)
    end

    DataPack.flush(npack)
end


function oper_act_56_get_value_arrive(sysarg, value)
    if value <= 0 then
        return
    end

    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_56_start then
        return
    end
    if not ssVar.oper_act_56_cmd then
        return
    end
    if not ssVar.oper_act_56_act then
        return
    end
    
    local cfg = get_oper_act_cfg(ssVar.oper_act_56_cmd, ssVar.oper_act_56_act)
    if not cfg then
        return
    end

    local config = cfg.config
    if not config then
        return
    end 
    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_56, 1)

    local myData = BaseFuc_unserialize(data)
    

    if not myData then
        myData = {}
    end

    if not myData.myUseCount then
        myData.myUseCount = 0
    end

    if not myData.myBuyCount then
        myData.myBuyCount = 0
    end

    if not myData.myConsumeMoney then
        myData.myConsumeMoney = 0
    end

    if not myData.myActivityVal then
        myData.myActivityVal = 0 
    end

    if not myData.myNumbers then
        myData.myNumbers = {}
    end

    if not myData.myScore then
        myData.myScore = 0
    end

    local time = System.getSystemTime()

    if myData.mySelfTime and not System.isUnixTimeSameDay(myData.mySelfTime, time) then
        myData.myActivityVal = 0 
        myData.myConsumeMoney = 0
        myData.myUseCount = 0
    end

    if not myData.finishLine then
        myData.finishLine = {}
    end

    if not myData.exAwards then
        myData.exAwards = {}
    end

    local count = oper_act_56_get_count(config, myData.myActivityVal, myData.myConsumeMoney)
    myData.myActivityVal = value
    local newcount = oper_act_56_get_count(config, myData.myActivityVal, myData.myConsumeMoney)

    if not myData.cmd_id then
        myData.cmd_id = cfg.cmd_id
        myData.act_id = cfg.act_id
        myData.time = time
    end

    myData.mySelfTime = time

    local newData = BaseFuc_serialize(myData)
    gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_56, 1, newData)

    if newcount ~= count then
        oper_act_56_packet_data(sysarg, cfg)
    end

end

function oper_act_56_consumeyuanbao(sysarg, value)
    if value <= 0 then
        return
    end

    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_56_start then
        return
    end
    if not ssVar.oper_act_56_cmd then
        return
    end
    if not ssVar.oper_act_56_act then
        return
    end
    
    local cfg = get_oper_act_cfg(ssVar.oper_act_56_cmd, ssVar.oper_act_56_act)
    if not cfg then
        return
    end

    local config = cfg.config
    if not config then
        return
    end 
    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_56, 1)

    local myData = BaseFuc_unserialize(data)
    

    if not myData then
        myData = {}
    end

    if not myData.myUseCount then
        myData.myUseCount = 0
    end

    if not myData.myBuyCount then
        myData.myBuyCount = 0
    end

    if not myData.myConsumeMoney then
        myData.myConsumeMoney = 0
    end

    if not myData.myActivityVal then
        myData.myActivityVal = 0 
    end

    if not myData.myNumbers then
        myData.myNumbers = {}
    end

    if not myData.myScore then
        myData.myScore = 0
    end

    local time = System.getSystemTime()

    if myData.mySelfTime and not System.isUnixTimeSameDay(myData.mySelfTime, time) then
        myData.myActivityVal = 0 
        myData.myConsumeMoney = 0
        myData.myUseCount = 0
    end

    if not myData.finishLine then
        myData.finishLine = {}
    end

    if not myData.exAwards then
        myData.exAwards = {}
    end

    local count = oper_act_56_get_count(config, myData.myActivityVal, myData.myConsumeMoney)
    myData.myConsumeMoney = myData.myConsumeMoney + value
    local newcount = oper_act_56_get_count(config, myData.myActivityVal, myData.myConsumeMoney)
    if not myData.cmd_id then
        myData.cmd_id = cfg.cmd_id
        myData.act_id = cfg.act_id
        myData.time = time
    end

    myData.mySelfTime = time

    local newData = BaseFuc_serialize(myData)
    gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_56, 1, newData)

    if newcount ~= count then
        oper_act_56_packet_data(sysarg, cfg)
    end
end

function oper_act_56_get_count(config, myActivityVal, myConsumeMoney)
    local count = 0
    if not config then
        return count
    end
    for idx = 1, #config.eventList do
        local event = config.eventList[idx]
        if event.eventType == 1 and myActivityVal >= event.eventNum then
            count = count + event.addCount
        elseif event.eventType == 2 and myConsumeMoney >= event.eventNum then
            count = count + event.addCount
        end
    end
    return count
end

function oper_act_56_can_get_award(needNumList, myNumbers)
    local canGet = false
    if not needNumList then
        return canGet
    end
    if not myNumbers then
        return canGet
    end
    local hasNumber = {}
    for idx = 1, #myNumbers do
        hasNumber[myNumbers[idx]] = 1
    end
    canGet = true
    for ii = 1, #needNumList do
        if not hasNumber[needNumList[ii]] then
            canGet = false
            break
        end
    end
    return canGet
end